home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / Config / Container.php
PHP Script  |  2004-10-01  |  25KB  |  717 lines

  1. <?php
  2. // +---------------------------------------------------------------------+
  3. // | PHP Version 4                                                       |
  4. // +---------------------------------------------------------------------+
  5. // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group            |
  6. // +---------------------------------------------------------------------+
  7. // | This source file is subject to version 2.0 of the PHP license,      |
  8. // | that is bundled with this package in the file LICENSE, and is       |
  9. // | available at through the world-wide-web at                          |
  10. // | http://www.php.net/license/2_02.txt.                                |
  11. // | If you did not receive a copy of the PHP license and are unable to  |
  12. // | obtain it through the world-wide-web, please send a note to         |
  13. // | license@php.net so we can mail you a copy immediately.              |
  14. // +---------------------------------------------------------------------+
  15. // | Author: Bertrand Mansion <bmansion@mamasam.com>                     |
  16. // +---------------------------------------------------------------------+
  17. //
  18. // $Id: Container.php,v 1.33 2004/06/14 11:08:31 mansion Exp $
  19.  
  20. require_once('Config.php');
  21.  
  22. /**
  23. * Interface for Config containers
  24. *
  25. * @author   Bertrand Mansion <bmansion@mamasam.com>
  26. * @package  Config
  27. */
  28. class Config_Container {
  29.  
  30.     /**
  31.     * Container object type
  32.     * Ex: section, directive, comment, blank
  33.     * @var  string
  34.     */
  35.     var $type;
  36.  
  37.     /**
  38.     * Container object name
  39.     * @var  string
  40.     */
  41.     var $name = '';
  42.  
  43.     /**
  44.     * Container object content
  45.     * @var  string
  46.     */
  47.     var $content = '';
  48.  
  49.     /**
  50.     * Container object children
  51.     * @var  array
  52.     */
  53.     var $children = array();
  54.  
  55.     /**
  56.     * Reference to container object's parent
  57.     * @var  object
  58.     */
  59.     var $parent;
  60.     
  61.     /**
  62.     * Array of attributes for this item
  63.     * @var  array
  64.     */
  65.     var $attributes;
  66.  
  67.     /**
  68.     * Unique id to differenciate nodes
  69.     *
  70.     * This is used to compare nodes
  71.     * Will not be needed anymore when this class will use ZendEngine 2
  72.     *
  73.     * @var  int
  74.     */
  75.     var $_id;
  76.  
  77.     /**
  78.     * Constructor
  79.     *
  80.     * @param  string  $type       Type of container object
  81.     * @param  string  $name       Name of container object
  82.     * @param  string  $content    Content of container object
  83.     * @param  array   $attributes Array of attributes for container object
  84.     */
  85.     function Config_Container($type = 'section', $name = '', $content = '', $attributes = null)
  86.     {
  87.         $this->type       = $type;
  88.         $this->name       = $name;
  89.         $this->content    = $content;
  90.         $this->attributes = $attributes;
  91.         $this->parent     = null;
  92.         $this->_id        = uniqid($name.$type, true);
  93.     } // end constructor
  94.  
  95.     /**
  96.     * Create a child for this item.
  97.     * @param  string  $type       type of item: directive, section, comment, blank...
  98.     * @param  mixed   $item       item name
  99.     * @param  string  $content    item content
  100.     * @param  array   $attributes item attributes
  101.     * @param  string  $where      choose a position 'bottom', 'top', 'after', 'before'
  102.     * @param  object  $target     needed if you choose 'before' or 'after' for where
  103.     * @return object  reference to new item or Pear_Error
  104.     */
  105.     function &createItem($type, $name, $content, $attributes = null, $where = 'bottom', $target = null)
  106.     {
  107.         $item =& new Config_Container($type, $name, $content, $attributes);
  108.         $result =& $this->addItem($item, $where, $target);
  109.         return $result;
  110.     } // end func &createItem
  111.     
  112.     /**
  113.     * Adds an item to this item.
  114.     * @param  object   $item      a container object
  115.     * @param  string   $where     choose a position 'bottom', 'top', 'after', 'before'
  116.     * @param  object   $target    needed if you choose 'before' or 'after' in $where
  117.     * @return mixed    reference to added container on success, Pear_Error on error
  118.     */
  119.     function &addItem(&$item, $where = 'bottom', $target = null)
  120.     {
  121.         if ($this->type != 'section') {
  122.             return PEAR::raiseError('Config_Container::addItem must be called on a section type object.', null, PEAR_ERROR_RETURN);
  123.         }
  124.         if (is_null($target)) {
  125.             $target =& $this;
  126.         }
  127.         if (strtolower(get_class($target)) != 'config_container') {
  128.             return PEAR::raiseError('Target must be a Config_Container object in Config_Container::addItem.', null, PEAR_ERROR_RETURN);
  129.         }
  130.  
  131.         switch ($where) {
  132.             case 'before':
  133.                 $index = $target->getItemIndex();
  134.                 break;
  135.             case 'after':
  136.                 $index = $target->getItemIndex()+1;
  137.                 break;
  138.             case 'top':
  139.                 $index = 0;
  140.                 break;
  141.             case 'bottom':
  142.                 $index = -1;
  143.                 break;
  144.             default:
  145.                 return PEAR::raiseError('Use only top, bottom, before or after in Config_Container::addItem.', null, PEAR_ERROR_RETURN);
  146.         }
  147.         if (isset($index) && $index >= 0) {
  148.             array_splice($this->children, $index, 0, 'tmp');
  149.         } else {
  150.             $index = count($this->children);
  151.         }
  152.         $this->children[$index] =& $item;
  153.         $this->children[$index]->parent =& $this;
  154.  
  155.         return $item;
  156.     } // end func addItem
  157.  
  158.     /**
  159.     * Adds a comment to this item.
  160.     * This is a helper method that calls createItem
  161.     *
  162.     * @param  string    $content        Object content
  163.     * @param  string    $where          Position : 'top', 'bottom', 'before', 'after'
  164.     * @param  object    $target         Needed when $where is 'before' or 'after'
  165.     * @return object  reference to new item or Pear_Error
  166.     */
  167.     function &createComment($content = '', $where = 'bottom', $target = null)
  168.     {
  169.         return $this->createItem('comment', null, $content, null, $where, $target);
  170.     } // end func &createComment
  171.  
  172.     /**
  173.     * Adds a blank line to this item.
  174.     * This is a helper method that calls createItem
  175.     *
  176.     * @return object  reference to new item or Pear_Error
  177.     */
  178.     function &createBlank($where = 'bottom', $target = null)
  179.     {
  180.         return $this->createItem('blank', null, null, null, $where, $target);
  181.     } // end func &createBlank
  182.  
  183.     /**
  184.     * Adds a directive to this item.
  185.     * This is a helper method that calls createItem
  186.     *
  187.     * @param  string    $name           Name of new directive
  188.     * @param  string    $content        Content of new directive
  189.     * @param  mixed     $attributes     Directive attributes
  190.     * @param  string    $where          Position : 'top', 'bottom', 'before', 'after'
  191.     * @param  object    $target         Needed when $where is 'before' or 'after'
  192.     * @return object  reference to new item or Pear_Error
  193.     */
  194.     function &createDirective($name, $content, $attributes = null, $where = 'bottom', $target = null)
  195.     {
  196.         return $this->createItem('directive', $name, $content, $attributes, $where, $target);
  197.     } // end func &createDirective
  198.  
  199.     /**
  200.     * Adds a section to this item.
  201.     *
  202.     * This is a helper method that calls createItem
  203.     * If the section already exists, it won't create a new one. 
  204.     * It will return reference to existing item.
  205.     *
  206.     * @param  string    $name           Name of new section
  207.     * @param  array     $attributes     Section attributes
  208.     * @param  string    $where          Position : 'top', 'bottom', 'before', 'after'
  209.     * @param  object    $target         Needed when $where is 'before' or 'after'
  210.     * @return object  reference to new item or Pear_Error
  211.     */
  212.     function &createSection($name, $attributes = null, $where = 'bottom', $target = null)
  213.     {
  214.         return $this->createItem('section', $name, null, $attributes, $where, $target);
  215.     } // end func &createSection
  216.  
  217.     /**
  218.     * Tries to find the specified item(s) and returns the objects.
  219.     *
  220.     * Examples:
  221.     * $directives =& $obj->getItem('directive');
  222.     * $directive_bar_4 =& $obj->getItem('directive', 'bar', null, 4);
  223.     * $section_foo =& $obj->getItem('section', 'foo');
  224.     *
  225.     * This method can only be called on an object of type 'section'.
  226.     * Note that root is a section.
  227.     * This method is not recursive and tries to keep the current structure.
  228.     * For a deeper search, use searchPath()
  229.     *
  230.     * @param  string    $type        Type of item: directive, section, comment, blank...
  231.     * @param  mixed     $name        Item name
  232.     * @param  mixed     $content     Find item with this content
  233.     * @param  array     $attributes  Find item with attribute set to the given value
  234.     * @param  int       $index       Index of the item in the returned object list. If it is not set, will try to return the last item with this name.
  235.     * @return mixed  reference to item found or false when not found
  236.     * @see &searchPath()
  237.     */
  238.     function &getItem($type = null, $name = null, $content = null, $attributes = null, $index = -1)
  239.     {
  240.         if ($this->type != 'section') {
  241.             return PEAR::raiseError('Config_Container::getItem must be called on a section type object.', null, PEAR_ERROR_RETURN);
  242.         }
  243.         if (!is_null($type)) {
  244.             $testFields[] = 'type';
  245.         }
  246.         if (!is_null($name)) {
  247.             $testFields[] = 'name';
  248.         }
  249.         if (!is_null($content)) {
  250.             $testFields[] = 'content';
  251.         }
  252.         if (!is_null($attributes) && is_array($attributes)) {
  253.             $testFields[] = 'attributes';
  254.         }
  255.  
  256.         $itemsArr = array();
  257.         $fieldsToMatch = count($testFields);
  258.         for ($i = 0, $count = count($this->children); $i < $count; $i++) {
  259.             $match = 0;
  260.             reset($testFields);
  261.             foreach ($testFields as $field) {
  262.                 if ($field != 'attributes') {
  263.                     if ($this->children[$i]->$field == ${$field}) {
  264.                         $match++;
  265.                     }
  266.                 } else {
  267.                     // Look for attributes in array
  268.                     $attrToMatch = count($attributes);
  269.                     $attrMatch = 0;
  270.                     foreach ($attributes as $key => $value) {
  271.                         if (isset($this->children[$i]->attributes[$key]) &&
  272.                             $this->children[$i]->attributes[$key] == $value) {
  273.                             $attrMatch++;
  274.                         }
  275.                     }
  276.                     if ($attrMatch == $attrToMatch) {
  277.                         $match++;
  278.                     }
  279.                 }
  280.             }
  281.             if ($match == $fieldsToMatch) {
  282.                 $itemsArr[] =& $this->children[$i];
  283.             }
  284.         }
  285.         if ($index >= 0) {
  286.             if (isset($itemsArr[$index])) {
  287.                 return $itemsArr[$index];
  288.             } else {
  289.                 return false;
  290.             }
  291.         } else {
  292.             if ($count = count($itemsArr)) {
  293.                 return $itemsArr[$count-1];
  294.             } else {
  295.                 return false;
  296.             }
  297.         }
  298.     } // end func &getItem
  299.  
  300.     /**
  301.     * Finds a node using XPATH like format:
  302.     * 
  303.     * search format = array ( item,item,item,item)
  304.     * item = 'string' .. will match the <string of the xml element
  305.     * item = array('string',array('name'=>'xyz'))
  306.     *       .. will match <string name="xyz">
  307.     * 
  308.     * @param    mixed   Search path and attributes
  309.     * 
  310.     * @return   mixed   Config_Container object, array of Config_Container objects or false on failure.
  311.     * @access   public
  312.     */
  313.     function &searchPath($args)
  314.     {
  315.         if ($this->type != 'section') {
  316.             return PEAR::raiseError('Config_Container::searchPath must be called on a section type object.', null, PEAR_ERROR_RETURN);
  317.         }
  318.  
  319.         $arg = array_shift($args);
  320.  
  321.         if (is_array($arg)) {
  322.             $name = $arg[0];
  323.             $attributes = $arg[1];
  324.         } else {
  325.             $name = $arg;
  326.             $attributes = null;
  327.         }
  328.         // find all the matches for first..
  329.         $match =& $this->getItem(null, $name, null, $attributes);
  330.  
  331.         if (!$match) {
  332.             return false;
  333.         }
  334.         if (!empty($args)) {
  335.             return $match->searchPath($args);
  336.         }
  337.         return $match;
  338.     } // end func &searchPath
  339.  
  340.     /**
  341.     * Returns how many children this container has
  342.     *
  343.     * @param  string    $type    type of children counted
  344.     * @param  string    $name    name of children counted
  345.     * @return int  number of children found
  346.     */
  347.     function countChildren($type = null, $name = null)
  348.     {
  349.         if ($this->type != 'section') {
  350.             return PEAR::raiseError('Config_Container::getChildrenNum must be called on a section type object.', null, PEAR_ERROR_RETURN);
  351.         }
  352.         if (is_null($type) && is_null($name)) {
  353.             return count($this->children);
  354.         }
  355.         $count = 0;
  356.         if (isset($name) && isset($type)) {
  357.             for ($i = 0, $children = count($this->children); $i < $children; $i++) {
  358.                 if ($this->children[$i]->name == $name && 
  359.                     $this->children[$i]->type == $type) {
  360.                     $count++;
  361.                 }
  362.             }
  363.             return $count;
  364.         }
  365.         if (isset($type)) {
  366.             for ($i = 0, $children = count($this->children); $i < $children; $i++) {
  367.                 if ($this->children[$i]->type == $type) {
  368.                     $count++;
  369.                 }
  370.             }
  371.             return $count;
  372.         }
  373.         if (isset($name)) {
  374.             // Some directives can have the same name
  375.             for ($i = 0, $children = count($this->children); $i < $children; $i++) {
  376.                 if ($this->children[$i]->name == $name) {
  377.                     $count++;
  378.                 }
  379.             }
  380.             return $count;
  381.         }
  382.     } // end func &countChildren
  383.  
  384.     /**
  385.     * Deletes an item (section, directive, comment...) from the current object
  386.     * TODO: recursive remove in sub-sections
  387.     * @return mixed  true if object was removed, false if not, or PEAR_Error if root
  388.     */
  389.     function removeItem()
  390.     {
  391.         if ($this->isRoot()) {
  392.             return PEAR::raiseError('Cannot remove root item in Config_Container::removeItem.', null, PEAR_ERROR_RETURN);
  393.         }
  394.         $index = $this->getItemIndex();
  395.         if (!is_null($index)) {
  396.             array_splice($this->parent->children, $index, 1);
  397.             return true;
  398.         }
  399.         return false;
  400.     } // end func removeItem
  401.  
  402.     /**
  403.     * Returns the item index in its parent children array.
  404.     * @return int  returns int or null if root object
  405.     */
  406.     function getItemIndex()
  407.     {
  408.         if (is_object($this->parent)) {
  409.             // This will be optimized with Zend Engine 2
  410.             $pchildren =& $this->parent->children;
  411.             for ($i = 0, $count = count($pchildren); $i < $count; $i++) {
  412.                 if ($pchildren[$i]->_id == $this->_id) {
  413.                     return $i;
  414.                 }
  415.             }
  416.         }
  417.         return;
  418.     } // end func getItemIndex
  419.  
  420.     /**
  421.     * Returns the item rank in its parent children array
  422.     * according to other items with same type and name.
  423.     * @return int  returns int or null if root object
  424.     */
  425.     function getItemPosition()
  426.     {
  427.         if (is_object($this->parent)) {
  428.             $pchildren =& $this->parent->children;
  429.             for ($i = 0, $count = count($pchildren); $i < $count; $i++) {
  430.                 if ($pchildren[$i]->name == $this->name &&
  431.                     $pchildren[$i]->type == $this->type) {
  432.                     $obj[] =& $pchildren[$i];
  433.                 }
  434.             }
  435.             for ($i = 0, $count = count($obj); $i < $count; $i++) {
  436.                 if ($obj[$i]->_id == $this->_id) {
  437.                     return $i;
  438.                 }
  439.             }
  440.         }
  441.         return;
  442.     } // end func getItemPosition
  443.  
  444.     /**
  445.     * Returns the item parent object.
  446.     * @return object  returns reference to parent object or null if root object
  447.     */
  448.     function &getParent()
  449.     {
  450.         return $this->parent;
  451.     } // end func &getParent
  452.  
  453.     /**
  454.     * Returns the item parent object.
  455.     * @return mixed  returns reference to child object or false if child does not exist
  456.     */
  457.     function &getChild($index = 0)
  458.     {
  459.         if (!empty($this->children[$index])) {
  460.             return $this->children[$index];
  461.         } else {
  462.             return false;
  463.         }
  464.     } // end func &getChild
  465.  
  466.     /**
  467.     * Set this item's name.
  468.     * @return void
  469.     */
  470.     function setName($name)
  471.     {
  472.         $this->name = $name;
  473.     } // end func setName
  474.  
  475.     /**
  476.     * Get this item's name.
  477.     * @return string    item's name
  478.     */
  479.     function getName()
  480.     {
  481.         return $this->name;
  482.     } // end func getName
  483.  
  484.     /**
  485.     * Set this item's content.
  486.     * @return void
  487.     */
  488.     function setContent($content)
  489.     {
  490.         $this->content = $content;
  491.     } // end func setContent
  492.     
  493.     /**
  494.     * Get this item's content.
  495.     * @return string    item's content
  496.     */
  497.     function getContent()
  498.     {
  499.         return $this->content;
  500.     } // end func getContent
  501.  
  502.     /**
  503.     * Set this item's type.
  504.     * @return void
  505.     */
  506.     function setType($type)
  507.     {
  508.         $this->type = $type;
  509.     } // end func setType
  510.  
  511.     /**
  512.     * Get this item's type.
  513.     * @return string    item's type
  514.     */
  515.     function getType()
  516.     {
  517.         return $this->type;
  518.     } // end func getType
  519.  
  520.     /**
  521.     * Set this item's attributes.
  522.     * @param  array    $attributes        Array of attributes
  523.     * @return void
  524.     */
  525.     function setAttributes($attributes)
  526.     {
  527.         $this->attributes = $attributes;
  528.     } // end func setAttributes
  529.  
  530.     /**
  531.     * Set this item's attributes.
  532.     * @param  array    $attributes        Array of attributes
  533.     * @return void
  534.     */
  535.     function updateAttributes($attributes)
  536.     {
  537.         if (is_array($attributes)) {
  538.             foreach ($attributes as $key => $value) {
  539.                 $this->attributes[$key] = $value;
  540.             }
  541.         }
  542.     } // end func updateAttributes
  543.  
  544.     /**
  545.     * Get this item's attributes.
  546.     * @return array    item's attributes
  547.     */
  548.     function getAttributes()
  549.     {
  550.         return $this->attributes;
  551.     } // end func getAttributes
  552.     
  553.     /**
  554.     * Get one attribute value of this item
  555.     * @param  string   $attribute        Attribute key
  556.     * @return mixed    item's attribute value
  557.     */
  558.     function getAttribute($attribute)
  559.     {
  560.         if (isset($this->attributes[$attribute])) {
  561.             return $this->attributes[$attribute];
  562.         }
  563.         return null;
  564.     } // end func getAttribute
  565.  
  566.     /**
  567.     * Set a children directive content.
  568.     * This is an helper method calling getItem and addItem or setContent for you.
  569.     * If the directive does not exist, it will be created at the bottom.
  570.     *
  571.     * @param  string    $name        Name of the directive to look for
  572.     * @param  mixed     $content     New content
  573.     * @param  int       $index       Index of the directive to set,
  574.     *                                in case there are more than one directive
  575.     *                                with the same name
  576.     * @return object    newly set directive
  577.     */
  578.     function &setDirective($name, $content, $index = -1)
  579.     {
  580.         $item =& $this->getItem('directive', $name, null, null, $index);
  581.         if ($item === false || PEAR::isError($item)) {
  582.             // Directive does not exist, will create one
  583.             unset($item);
  584.             return $this->createDirective($name, $content, null);
  585.         } else {
  586.             // Change existing directive value
  587.             $item->setContent($content);
  588.             return $item;
  589.         }
  590.     } // end func setDirective
  591.  
  592.     /**
  593.     * Is this item root, in a config container object
  594.     * @return bool    true if item is root
  595.     */
  596.     function isRoot()
  597.     {
  598.         if (is_null($this->parent)) {
  599.             return true;
  600.         }
  601.         return false;
  602.     } // end func isRoot
  603.  
  604.     /**
  605.     * Call the toString methods in the container plugin
  606.     * @param    string  $configType  Type of configuration used to generate the string
  607.     * @param    array   $options     Specify special options used by the parser
  608.     * @return   mixed   true on success or PEAR_ERROR
  609.     */
  610.     function toString($configType, $options = array())
  611.     {
  612.         $configType = strtolower($configType);
  613.         if (!isset($GLOBALS['CONFIG_TYPES'][$configType])) {
  614.             return PEAR::raiseError("Configuration type '$configType' is not registered in Config_Container::toString.", null, PEAR_ERROR_RETURN);
  615.         }
  616.         $includeFile = $GLOBALS['CONFIG_TYPES'][$configType][0];
  617.         $className   = $GLOBALS['CONFIG_TYPES'][$configType][1];
  618.         include_once($includeFile);
  619.         $renderer = new $className($options);
  620.         return $renderer->toString($this);
  621.     } // end func toString
  622.  
  623.     /**
  624.     * Returns a key/value pair array of the container and its children.
  625.     *
  626.     * Format : section[directive][index] = value
  627.     * If the container has attributes, it will use '@' and '#'
  628.     * index is here because multiple directives can have the same name.
  629.     *
  630.     * @param    bool    $useAttr        Whether to return the attributes too
  631.     * @return array
  632.     */
  633.     function toArray($useAttr = true)
  634.     {
  635.         $array[$this->name] = array();
  636.         switch ($this->type) {
  637.             case 'directive':
  638.                 if ($useAttr && count($this->attributes) > 0) {
  639.                     $array[$this->name]['#'] = $this->content;
  640.                     $array[$this->name]['@'] = $this->attributes;
  641.                 } else {
  642.                     $array[$this->name] = $this->content;
  643.                 }
  644.                 break;
  645.             case 'section':
  646.                 if ($useAttr && count($this->attributes) > 0) {
  647.                     $array[$this->name]['@'] = $this->attributes;
  648.                 }
  649.                 if ($count = count($this->children)) {
  650.                     for ($i = 0; $i < $count; $i++) {
  651.                         $newArr = $this->children[$i]->toArray($useAttr);
  652.                         if (!is_null($newArr)) {
  653.                             foreach ($newArr as $key => $value) {
  654.                                 if (isset($array[$this->name][$key])) {
  655.                                     // duplicate name/type
  656.                                     if (!is_array($array[$this->name][$key]) ||
  657.                                         !isset($array[$this->name][$key][0])) {
  658.                                         $old = $array[$this->name][$key];
  659.                                         unset($array[$this->name][$key]);
  660.                                         $array[$this->name][$key][0] = $old;
  661.                                     }
  662.                                     $array[$this->name][$key][] = $value;
  663.                                 } else {
  664.                                     $array[$this->name][$key] = $value;
  665.                                 }
  666.                             }
  667.                         }
  668.                     }
  669.                 }
  670.                 break;
  671.             default:
  672.                 return null;
  673.         }
  674.         return $array;
  675.     } // end func toArray
  676.     
  677.     /**
  678.     * Writes the configuration to a file
  679.     * 
  680.     * @param  mixed  $datasrc        Info on datasource such as path to the configuraton file or dsn...
  681.     * @param  string $configType     Type of configuration
  682.     * @param  array  $options        Options for writer
  683.     * @access public
  684.     * @return mixed     true on success or PEAR_ERROR
  685.     */
  686.     function writeDatasrc($datasrc, $configType, $options = array())
  687.     {
  688.         $configType = strtolower($configType);
  689.         if (!isset($GLOBALS['CONFIG_TYPES'][$configType])) {
  690.             return PEAR::raiseError("Configuration type '$configType' is not registered in Config_Container::writeDatasrc.", null, PEAR_ERROR_RETURN);
  691.         }
  692.         $includeFile = $GLOBALS['CONFIG_TYPES'][$configType][0];
  693.         $className = $GLOBALS['CONFIG_TYPES'][$configType][1];
  694.         include_once($includeFile);
  695.  
  696.         $writeMethodName = (version_compare(phpversion(), '5', '<')) ? 'writedatasrc' : 'writeDatasrc';
  697.         if (in_array($writeMethodName, get_class_methods($className))) {
  698.             $writer = new $className($options);
  699.             return $writer->writeDatasrc($datasrc, $this);
  700.         }
  701.  
  702.         // Default behaviour
  703.         $fp = @fopen($datasrc, 'w');
  704.         if ($fp) {
  705.             $string = $this->toString($configType, $options);
  706.             $len = strlen($string);
  707.             @flock($fp, LOCK_EX);
  708.             @fwrite($fp, $string, $len);
  709.             @flock($fp, LOCK_UN);
  710.             @fclose($fp);
  711.             return true;
  712.         } else {
  713.             return PEAR::raiseError('Cannot open datasource for writing.', 1, PEAR_ERROR_RETURN);
  714.         }
  715.     } // end func writeDatasrc
  716. } // end class Config_Container
  717. ?>